package com.fw.service.serviceprofile.impl;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;

import com.fw.service.applicationlog.ApplicationLogService;
import com.fw.service.applicationlog.bean.ApplicationLogBean;
import com.fw.service.auditlog.AuditLogService;
import com.fw.service.auditlog.bean.AuditLogBean;
import com.fw.service.bean.EntryBean;
import com.fw.service.bean.ErrorBean;
import com.fw.service.bean.SearchCriteriaBean;
import com.fw.service.bean.SearchResultBean;
import com.fw.service.formvalidator.FormValidatorService;
import com.fw.service.masterdata.MasterDataService;
import com.fw.service.persistence.MerchantProfilePersistenceService;
import com.fw.service.persistence.ServiceProfilePersistenceService;
import com.fw.service.persistence.dto.Error;
import com.fw.service.persistence.dto.MerchantProfile;
import com.fw.service.persistence.dto.ServiceProfile;
import com.fw.service.property.PropertyService;
import com.fw.service.serviceprofile.ServiceProfileService;
import com.fw.service.serviceprofile.bean.SearchServiceProfileBean;
import com.fw.service.serviceprofile.bean.ServiceProfileBean;
import com.fw.service.serviceprofile.template.ServiceProfileCSVTemplate;
import com.fw.util.DataUtils;
import com.fw.util.DateUtils;
import com.fw.util.PageRequestUtils;
import com.fw.util.StringUtils;
import com.fw.util.VelocityUtil;

public class ServiceProfileServiceImpl implements ServiceProfileService {

    private static Logger log = Logger.getLogger(ServiceProfileServiceImpl.class.getName());

    @Autowired
    private PropertyService propertyService;

    @Autowired
    private MasterDataService masterDataService;

    @Autowired
    private ApplicationLogService applicationLogService;

    @Autowired
    private AuditLogService auditLogService;

    @Autowired
    private FormValidatorService formValidatorService;

    @Autowired
    private MerchantProfilePersistenceService merchantProfilePersistenceService;

    @Autowired
    private ServiceProfilePersistenceService serviceProfilePersistenceService;

    @Override
    public List<EntryBean<String, Serializable>> createServiceProfile(ServiceProfileBean serviceProfileBean) {
	String clazz = ServiceProfileService.class.getName();
	String method = "createServiceProfile";
	List<EntryBean<String, Serializable>> entryBeans = null;
	try {
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(method);
	    applicationLogService.createApplicationLog(applicationLogBean);

	    if (serviceProfileBean != null) {
		entryBeans = new ArrayList<EntryBean<String, Serializable>>();
		// validate
		List<Error> errors = formValidatorService.validate(clazz, method, serviceProfileBean);
		List<ErrorBean> errorBeans = new ArrayList<ErrorBean>();
		if (errors != null && !errors.isEmpty()) {
		    for (Error error : errors) {
			ErrorBean errorBean = new ErrorBean();
			BeanUtils.copyProperties(error, errorBean);
			errorBeans.add(errorBean);
		    }
		}
		// validate unique
		if (!this.checkUniqueServiceId(serviceProfileBean.getServiceId())) {
		    ErrorBean errorBean = new ErrorBean();
		    errorBean
			    .setErrorCode("errors.com.fw.service.serviceprofile.ServiceProfileService.createServiceProfile.serviceIdExist");
		    errorBeans.add(errorBean);
		}
		if (errorBeans != null && !errorBeans.isEmpty()) {
		    entryBeans.add(new EntryBean<String, Serializable>(List.class.getName() + "." + ErrorBean.class.getName(),
			    (Serializable) errorBeans));
		} else {
		    Date currentDate = DateUtils.getCurrentDate();
		    String currentDateStr = StringUtils.formatDate(currentDate, StringUtils.PATTERN_DATETIME_PERSISTENCE);
		    // save
		    ServiceProfile serviceProfile = new ServiceProfile();
		    BeanUtils.copyProperties(serviceProfileBean, serviceProfile);
		    // update fk to merchant profile
		    List<MerchantProfile> merchantProfiles = merchantProfilePersistenceService.selectByMerchantIdAndStatus(
			    serviceProfileBean.getMerchantId(), null);
		    if (merchantProfiles != null && !merchantProfiles.isEmpty()) {
			MerchantProfile merchantProfile = merchantProfiles.get(0);
			serviceProfile.setMerchantProfile(merchantProfile);
		    }
		    serviceProfile.setServiceType(ServiceProfile.SERVICE_TYPE_CASH);
		    serviceProfile.setCreateBy(serviceProfileBean.getLoginUsername());
		    serviceProfile.setCreateDate(currentDateStr);
		    serviceProfile.setLastUpdateBy(serviceProfileBean.getLoginUsername());
		    serviceProfile.setLastUpdateDate(currentDateStr);
		    serviceProfile = serviceProfilePersistenceService.save(serviceProfile);

		    ServiceProfileBean resultServiceProfileBean = new ServiceProfileBean();
		    BeanUtils.copyProperties(serviceProfile, resultServiceProfileBean);
		    resultServiceProfileBean.setId(serviceProfile.getId());
		    // audit log
		    String logActionType = propertyService.getProperty("auditlog." + clazz + "." + method);
		    if (logActionType != null) {
			AuditLogBean auditLogBean = new AuditLogBean();
			auditLogBean.setLogActionType(logActionType);
			auditLogBean.setDescription(serviceProfileBean.getServiceId() + " created by "
				+ serviceProfileBean.getLoginUsername());
			auditLogBean.setGroupId(serviceProfileBean.getLoginRoleId());
			auditLogBean.setUserId(serviceProfileBean.getLoginUserId());
			auditLogBean.setDateTime(currentDateStr);
			auditLogBean.setUserIp(serviceProfileBean.getUserIp());
			auditLogService.createAuditLog(auditLogBean);
		    }
		    entryBeans.add(new EntryBean<String, Serializable>(resultServiceProfileBean.getClass().getName(),
			    resultServiceProfileBean));
		}
	    }
	} catch (Exception e) {
	    log.error(e, e);
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return entryBeans;
    }

    @Override
    public ServiceProfileBean getServiceProfile(Long id) {
	ServiceProfileBean serviceProfileBean = null;
	try {
	    ServiceProfile serviceProfile = serviceProfilePersistenceService.findOne(id);
	    if (serviceProfile != null && !ServiceProfile.STATUS_CLOSED.equals(serviceProfile.getServiceStatus())) {
		serviceProfileBean = new ServiceProfileBean();
		BeanUtils.copyProperties(serviceProfile, serviceProfileBean);
		serviceProfileBean.setId(serviceProfile.getId());
	    }
	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}
	return serviceProfileBean;
    }

    @Override
    public List<EntryBean<String, Serializable>> updateServiceProfile(ServiceProfileBean serviceProfileBean) {
	String clazz = ServiceProfileService.class.getName();
	String method = "updateServiceProfile";
	List<EntryBean<String, Serializable>> entryBeans = null;
	ServiceProfile serviceProfile = null;
	try {
	    if (serviceProfileBean != null) {
		serviceProfile = serviceProfilePersistenceService.findOne(serviceProfileBean.getId());
		if (serviceProfile != null && isDataChange(serviceProfile, serviceProfileBean)) {

		    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
		    applicationLogBean.setType(ApplicationLogBean.TYPE_INFO);
		    applicationLogBean.setClazz(clazz);
		    applicationLogBean.setMethod(method);
		    applicationLogBean.setMessage(method);
		    applicationLogService.createApplicationLog(applicationLogBean);

		    entryBeans = new ArrayList<EntryBean<String, Serializable>>();
		    // validate
		    List<Error> errors = formValidatorService.validate(clazz, method, serviceProfileBean);
		    List<ErrorBean> errorBeans = new ArrayList<ErrorBean>();
		    if (errors != null && !errors.isEmpty()) {
			for (Error error : errors) {
			    ErrorBean errorBean = new ErrorBean();
			    BeanUtils.copyProperties(error, errorBean);
			    errorBeans.add(errorBean);
			}
		    }
		    if (errorBeans != null && !errorBeans.isEmpty()) {
			entryBeans.add(new EntryBean<String, Serializable>(List.class.getName() + "." + ErrorBean.class.getName(),
				(Serializable) errorBeans));
		    } else {
			// if (merchantProfile != null && !MerchantProfile.STATUS_INACTIVE.equals(merchantProfile.getStatus())) {
			Date currentDate = DateUtils.getCurrentDate();
			String currentDateStr = StringUtils.formatDate(currentDate, StringUtils.PATTERN_DATETIME_PERSISTENCE);
			// copy from bean
			BeanUtils.copyProperties(serviceProfileBean, serviceProfile, "id");
			serviceProfile.setLastUpdateBy(serviceProfileBean.getLoginUsername());
			serviceProfile.setLastUpdateDate(currentDateStr);
			serviceProfile = serviceProfilePersistenceService.save(serviceProfile);
			ServiceProfileBean resultServiceProfileBean = new ServiceProfileBean();
			BeanUtils.copyProperties(serviceProfile, resultServiceProfileBean);
			resultServiceProfileBean.setId(serviceProfile.getId());

			// audit log
			String logActionType = propertyService.getProperty("auditlog." + clazz + "." + method);
			if (logActionType != null) {
			    AuditLogBean auditLogBean = new AuditLogBean();
			    auditLogBean.setLogActionType(logActionType);
			    auditLogBean.setDescription(serviceProfileBean.getServiceId() + " : " + serviceProfileBean.getMerchantId()
				    + " updated by " + serviceProfileBean.getLoginUsername());
			    auditLogBean.setGroupId(serviceProfileBean.getLoginRoleId());
			    auditLogBean.setUserId(serviceProfileBean.getLoginUserId());
			    auditLogBean.setDateTime(currentDateStr);
			    auditLogBean.setUserIp(serviceProfileBean.getUserIp());
			    auditLogService.createAuditLog(auditLogBean);
			}
			entryBeans.add(new EntryBean<String, Serializable>(resultServiceProfileBean.getClass().getName(),
				resultServiceProfileBean));
			// }
		    }
		} else {
		    entryBeans = new ArrayList<EntryBean<String, Serializable>>();
		    entryBeans.add(new EntryBean<String, Serializable>(serviceProfileBean.getClass().getName(), serviceProfileBean));
		}
	    }
	} catch (Exception e) {
	    log.error(e, e);
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return entryBeans;
    }

    @Override
    public List<EntryBean<String, Serializable>> deleteServiceProfile(ServiceProfileBean serviceProfileBean) {
	String clazz = ServiceProfileService.class.getName();
	String method = "deleteServiceProfile";
	List<EntryBean<String, Serializable>> entryBeans = null;
	ServiceProfile serviceProfile = null;
	try {
	    if (serviceProfileBean != null) {
		Date currentDate = DateUtils.getCurrentDate();
		String currentDateStr = StringUtils.formatDate(currentDate, StringUtils.PATTERN_DATETIME_PERSISTENCE);
		entryBeans = new ArrayList<EntryBean<String, Serializable>>();

		// validate
		List<Error> errors = formValidatorService.validate(clazz, method, serviceProfileBean);
		List<ErrorBean> errorBeans = new ArrayList<ErrorBean>();
		if (errors != null && !errors.isEmpty()) {
		    for (Error error : errors) {
			ErrorBean errorBean = new ErrorBean();
			BeanUtils.copyProperties(error, errorBean);
			errorBeans.add(errorBean);
		    }
		} else {
		    Long serviceProfileId = serviceProfileBean.getId();
		    serviceProfile = serviceProfilePersistenceService.findOne(serviceProfileId);
		    if (serviceProfile == null) {
			errorBeans.add(new ErrorBean(
				"errors.com.fw.service.serviceprofile.ServiceProfileService.deleteServiceProfile.notfoundServiceProfile"));
		    }
		}
		// result
		if (errorBeans != null && !errorBeans.isEmpty()) {
		    entryBeans.add(new EntryBean<String, Serializable>(List.class.getName() + "." + ErrorBean.class.getName(),
			    (Serializable) errorBeans));
		} else {

		    // update status
		    serviceProfile.setServiceStatus(ServiceProfile.STATUS_INACTIVE);
		    serviceProfile.setLastUpdateBy(serviceProfileBean.getLoginUsername());
		    serviceProfile.setLastUpdateDate(currentDateStr);
		    serviceProfile = serviceProfilePersistenceService.save(serviceProfile);

		    ServiceProfileBean resultServiceProfileBean = new ServiceProfileBean();
		    BeanUtils.copyProperties(serviceProfile, resultServiceProfileBean);
		    resultServiceProfileBean.setId(serviceProfile.getId());

		    // audit log
		    String logActionType = propertyService.getProperty("auditlog." + clazz + "." + method);
		    if (logActionType != null) {
			AuditLogBean auditLogBean = new AuditLogBean();
			auditLogBean.setLogActionType(logActionType);
			auditLogBean.setDescription("Service Profile, Service ID: " + serviceProfile.getServiceId() + " deleted by "
				+ serviceProfileBean.getLoginUsername());
			auditLogBean.setGroupId(serviceProfileBean.getLoginRoleId());
			auditLogBean.setUserId(serviceProfileBean.getLoginUserId());
			auditLogBean.setDateTime(currentDateStr);
			auditLogBean.setUserIp(serviceProfileBean.getUserIp());
			auditLogService.createAuditLog(auditLogBean);
		    }
		    entryBeans.add(new EntryBean<String, Serializable>(resultServiceProfileBean.getClass().getName(),
			    resultServiceProfileBean));
		}
	    }
	} catch (Exception e) {
	    log.error(e, e);
	    ApplicationLogBean applicationLogBean = new ApplicationLogBean();
	    applicationLogBean.setType(ApplicationLogBean.TYPE_ERROR);
	    applicationLogBean.setClazz(clazz);
	    applicationLogBean.setMethod(method);
	    applicationLogBean.setMessage(e.getMessage());
	    applicationLogService.createApplicationLog(applicationLogBean);
	}
	return entryBeans;
    }

    @Override
    public Boolean checkUniqueServiceId(String serviceId) {
	Boolean result = Boolean.FALSE;
	try {
	    List<ServiceProfile> serviceProfiles = serviceProfilePersistenceService.selectByServiceIdAndStatus(serviceId, null);
	    if (serviceProfiles == null || serviceProfiles.isEmpty()) {
		result = Boolean.TRUE;
	    }
	} catch (Exception e) {
	    log.error(e, e);
	}
	return result;
    }

    @Override
    public SearchResultBean<ServiceProfileBean> selectServiceProfile(SearchCriteriaBean<SearchServiceProfileBean> searchCriteriaBean) {
	SearchResultBean<ServiceProfileBean> searchResultBean = null;
	try {
	    if (searchCriteriaBean != null) {
		SearchServiceProfileBean searchServiceProfileBean = searchCriteriaBean.getCriteriaBean();
		if (searchServiceProfileBean != null) {
		    Page<ServiceProfile> page = serviceProfilePersistenceService.findAll(this.getSpecification(searchServiceProfileBean),
			    PageRequestUtils.getPageRequest(searchCriteriaBean));
		    if (page != null) {
			searchResultBean = new SearchResultBean<ServiceProfileBean>();
			searchResultBean.setTotalElements(page.getTotalElements());
			searchResultBean.setTotalPages(page.getTotalPages());
			List<ServiceProfileBean> content = new ArrayList<ServiceProfileBean>();
			List<ServiceProfile> serviceProfiles = page.getContent();
			if (serviceProfiles != null && !serviceProfiles.isEmpty()) {
			    for (ServiceProfile serviceProfile : serviceProfiles) {
				ServiceProfileBean bean = new ServiceProfileBean();
				BeanUtils.copyProperties(serviceProfile, bean);
				MerchantProfile merchantProfile = serviceProfile.getMerchantProfile();
				if (merchantProfile != null) {
				    bean.setMerchantNameEn(merchantProfile.getMerchantNameEn());
				    bean.setCompanyNameEn(merchantProfile.getCompanyNameEn());
				    bean.setMerchantServiceType(merchantProfile.getMerchantServiceType());
				    bean.setMerchantUrl(merchantProfile.getUrl());
				}
				bean.setId(serviceProfile.getId());
				content.add(bean);
			    }
			}
			searchResultBean.setContent(content);
		    }
		}
	    }
	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}
	return searchResultBean;
    }

    private boolean isDataChange(ServiceProfile serviceProfile, ServiceProfileBean serviceProfileBean) {
	boolean isChange = false;
	if (serviceProfile != null && serviceProfileBean != null) {
	    if (// service information
	    DataUtils.isChange(serviceProfile.getIsTestService(), serviceProfileBean.getIsTestService())
		    || DataUtils.isChange(serviceProfile.getServiceStatus(), serviceProfileBean.getServiceStatus())
		    || DataUtils.isChange(serviceProfile.getServiceType(), serviceProfileBean.getServiceType())
		    || DataUtils.isChange(serviceProfile.getHost(), serviceProfileBean.getHost())
		    || DataUtils.isChange(serviceProfile.getIsBankGuarantee(), serviceProfileBean.getIsBankGuarantee())
		    || DataUtils.isChange(serviceProfile.getBankGuarantee(), serviceProfileBean.getBankGuarantee())
		    || DataUtils.isChange(serviceProfile.getBankGuaranteeExpireDate(), serviceProfileBean.getBankGuaranteeExpireDate())
		    || DataUtils.isChange(serviceProfile.getChequeName(), serviceProfileBean.getChequeName())
		    || DataUtils.isChange(serviceProfile.getLaunchedDate(), serviceProfileBean.getLaunchedDate())
		    || DataUtils.isChange(serviceProfile.getIsResponseUrlBack(), serviceProfileBean.getIsResponseUrlBack())
		    || DataUtils.isChange(serviceProfile.getResponseUrlBack(), serviceProfileBean.getResponseUrlBack())
		    || DataUtils.isChange(serviceProfile.getIsSuccessUrl(), serviceProfileBean.getIsSuccessUrl())
		    || DataUtils.isChange(serviceProfile.getSuccessUrl(), serviceProfileBean.getSuccessUrl())
		    || DataUtils.isChange(serviceProfile.getIsNotifyCustomer(), serviceProfileBean.getIsNotifyCustomer())
		    || DataUtils.isChange(serviceProfile.getIsFailUrl(), serviceProfileBean.getIsFailUrl())
		    || DataUtils.isChange(serviceProfile.getFailUrl(), serviceProfileBean.getFailUrl())
		    || DataUtils.isChange(serviceProfile.getIsCancelUrl(), serviceProfileBean.getIsCancelUrl())
		    || DataUtils.isChange(serviceProfile.getCancelUrl(), serviceProfileBean.getCancelUrl())
		    // payment service
		    || DataUtils.isChange(serviceProfile.getInvoiceAging(), serviceProfileBean.getInvoiceAging())
		    || DataUtils.isChange(serviceProfile.getIsBypassInvoiceAging(), serviceProfileBean.getIsBypassInvoiceAging())
		    || DataUtils.isChange(serviceProfile.getBankCodeAndName(), serviceProfileBean.getBankCodeAndName())
		    || DataUtils.isChange(serviceProfile.getBankAccountNo(), serviceProfileBean.getBankAccountNo())
		    || DataUtils.isChange(serviceProfile.getSapArCode(), serviceProfileBean.getSapArCode())
		    || DataUtils.isChange(serviceProfile.getSapApCode(), serviceProfileBean.getSapApCode())
		    || DataUtils.isChange(serviceProfile.getMessageSlip1(), serviceProfileBean.getMessageSlip1())
		    || DataUtils.isChange(serviceProfile.getMessageSlip2(), serviceProfileBean.getMessageSlip2())
		    || DataUtils.isChange(serviceProfile.getMdr(), serviceProfileBean.getMdr())
		    || DataUtils.isChange(serviceProfile.getServiceFee(), serviceProfileBean.getServiceFee())
		    // payment limit
		    || DataUtils.isChange(serviceProfile.getDailyLimit(), serviceProfileBean.getDailyLimit())
		    || DataUtils.isChange(serviceProfile.getMonthlyLimit(), serviceProfileBean.getMonthlyLimit())
		    || DataUtils.isChange(serviceProfile.getTransactionAmountLimit(), serviceProfileBean.getTransactionAmountLimit())
		    // service contact person
		    || DataUtils.isChange(serviceProfile.getContact1Name(), serviceProfileBean.getContact1Name())
		    || DataUtils.isChange(serviceProfile.getContact1Phone(), serviceProfileBean.getContact1Phone())
		    || DataUtils.isChange(serviceProfile.getContact1Mobile(), serviceProfileBean.getContact1Mobile())
		    || DataUtils.isChange(serviceProfile.getContact1Email(), serviceProfileBean.getContact1Email())
		    || DataUtils.isChange(serviceProfile.getContact2Name(), serviceProfileBean.getContact2Name())
		    || DataUtils.isChange(serviceProfile.getContact2Phone(), serviceProfileBean.getContact2Phone())
		    || DataUtils.isChange(serviceProfile.getContact2Mobile(), serviceProfileBean.getContact2Mobile())
		    || DataUtils.isChange(serviceProfile.getContact2Email(), serviceProfileBean.getContact2Email())
		    || DataUtils.isChange(serviceProfile.getContact3Name(), serviceProfileBean.getContact3Name())
		    || DataUtils.isChange(serviceProfile.getContact3Phone(), serviceProfileBean.getContact3Phone())
		    || DataUtils.isChange(serviceProfile.getContact3Mobile(), serviceProfileBean.getContact3Mobile())
		    || DataUtils.isChange(serviceProfile.getContact3Email(), serviceProfileBean.getContact3Email())
		    || DataUtils.isChange(serviceProfile.getContact4Name(), serviceProfileBean.getContact4Name())
		    || DataUtils.isChange(serviceProfile.getContact4Phone(), serviceProfileBean.getContact4Phone())
		    || DataUtils.isChange(serviceProfile.getContact4Mobile(), serviceProfileBean.getContact4Mobile())
		    || DataUtils.isChange(serviceProfile.getContact4Email(), serviceProfileBean.getContact4Email())) {
		isChange = true;
	    }
	}
	return isChange;
    }

    private Specification<ServiceProfile> getSpecification(SearchServiceProfileBean searchServiceProfileBean) {
	final String serviceId = searchServiceProfileBean.getServiceId();
	final String merchantId = searchServiceProfileBean.getMerchantId();
	final String merchantName = searchServiceProfileBean.getMerchantName();
	final String companyName = searchServiceProfileBean.getCompanyName();
	final String projectContact = searchServiceProfileBean.getProjectContact();
	final Boolean hideServiceTest = searchServiceProfileBean.getHideServiceTest();
	final Date bankGuaranteeExpireDateFrom = searchServiceProfileBean.getBankGuaranteeExpireDateFrom();
	final Date bankGuaranteeExpireDateTo = searchServiceProfileBean.getBankGuaranteeExpireDateTo();
	final Date launchedDateFrom = searchServiceProfileBean.getLaunchedDateFrom();
	final Date launchedDateTo = searchServiceProfileBean.getLaunchedDateTo();
	final String mdr = searchServiceProfileBean.getMdr();
	final String serviceFee = searchServiceProfileBean.getServiceFee();
	final String serviceStatus = searchServiceProfileBean.getServiceStatus();
	final String serviceType = searchServiceProfileBean.getServiceType();
	final String host = searchServiceProfileBean.getHost();

	Specification<ServiceProfile> specification = new Specification<ServiceProfile>() {
	    @Override
	    public Predicate toPredicate(Root<ServiceProfile> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		List<Predicate> predicates = new ArrayList<Predicate>();
		if (serviceId != null && !serviceId.isEmpty()) {
		    predicates.add(cb.like(root.<String> get("serviceId"), "%" + serviceId + "%"));
		}
		if (merchantId != null && !merchantId.isEmpty()) {
		    predicates.add(cb.like(root.<String> get("merchantId"), "%" + merchantId + "%"));
		}
		Join<ServiceProfile, MerchantProfile> merchantProfile = null;
		if (merchantName != null && !merchantName.isEmpty() || companyName != null && !companyName.isEmpty()) {
		    merchantProfile = root.join("merchantProfile");
		}
		if (merchantName != null && !merchantName.isEmpty()) {
		    predicates.add(cb.like(merchantProfile.<String> get("merchantNameEn"), "%" + merchantName + "%"));
		}
		if (companyName != null && !companyName.isEmpty()) {
		    predicates.add(cb.like(merchantProfile.<String> get("companyNameEn"), "%" + companyName + "%"));
		}
		if (projectContact != null && !projectContact.isEmpty()) {
		    predicates.add(cb.like(root.<String> get("contact1Name"), "%" + projectContact + "%"));
		}
		if (hideServiceTest != null && hideServiceTest.booleanValue()) {
		    predicates.add(cb.notEqual(root.<Boolean> get("isTestService"), hideServiceTest));
		}
		if (bankGuaranteeExpireDateFrom != null) {
		    predicates.add(cb.greaterThanOrEqualTo(root.<String> get("bankGuaranteeExpireDate"),
			    StringUtils.formatDate(bankGuaranteeExpireDateFrom, StringUtils.PATTERN_MONTH_YEAR_PERSISTENCE)));
		}
		if (bankGuaranteeExpireDateTo != null) {
		    predicates.add(cb.lessThanOrEqualTo(root.<String> get("bankGuaranteeExpireDate"),
			    StringUtils.formatDate(bankGuaranteeExpireDateTo, StringUtils.PATTERN_MONTH_YEAR_PERSISTENCE)));
		}
		if (launchedDateFrom != null) {
		    predicates.add(cb.greaterThanOrEqualTo(root.<String> get("launchedDate"),
			    StringUtils.formatDate(launchedDateFrom, StringUtils.PATTERN_DATE_PERSISTENCE)));
		}
		if (launchedDateTo != null) {
		    predicates.add(cb.lessThanOrEqualTo(root.<String> get("launchedDate"),
			    StringUtils.formatDate(launchedDateTo, StringUtils.PATTERN_DATE_PERSISTENCE)));
		}
		if (mdr != null && !mdr.isEmpty()) {
		    predicates.add(cb.like(root.<String> get("mdr"), "%" + mdr + "%"));
		}
		if (serviceFee != null && !serviceFee.isEmpty()) {
		    predicates.add(cb.like(root.<String> get("serviceFee"), "%" + serviceFee + "%"));
		}
		if (serviceStatus != null && !serviceStatus.isEmpty()) {
		    predicates.add(cb.equal(root.<String> get("serviceStatus"), serviceStatus));
		} else {
		    predicates.add(cb.notEqual(root.<String> get("serviceStatus"), ServiceProfile.STATUS_CLOSED));
		}
		if (serviceType != null && !serviceType.isEmpty()) {
		    predicates.add(cb.equal(root.<String> get("serviceType"), serviceType));
		}
		if (host != null && !host.isEmpty()) {
		    predicates.add(cb.equal(root.<String> get("host"), host));
		}
		Predicate result = cb.conjunction();
		for (Predicate predicate : predicates) {
		    result.getExpressions().add(predicate);
		}
		return result;
	    }
	};
	return specification;
    }

    @Override
    public byte[] exportServiceProfileAsCSV(SearchCriteriaBean<SearchServiceProfileBean> searchCriteriaBean) {
	byte[] result = null;
	try {
	    if (searchCriteriaBean != null) {
		SearchServiceProfileBean searchServiceProfileBean = searchCriteriaBean.getCriteriaBean();
		if (searchServiceProfileBean != null) {

		    searchCriteriaBean.setPage(1);
		    searchCriteriaBean.setSize(Integer.MAX_VALUE);

		    Page<ServiceProfile> page = serviceProfilePersistenceService.findAll(this.getSpecification(searchServiceProfileBean),
			    PageRequestUtils.getPageRequest(searchCriteriaBean));
		    if (page != null) {

			Map<String, String> statusMap = new HashMap<String, String>();
			Map<String, String> serviceTypeMap = new HashMap<String, String>();
			Map<String, String> merchantServiceTypeMap = new HashMap<String, String>();

			List<EntryBean<String, String>> entryBeanServiceTypes = masterDataService.selectAllServiceProfilePaymentType();
			List<EntryBean<String, String>> entryBeanStatus = masterDataService.selectAllServiceProfileStatus();
			List<EntryBean<String, String>> entryBeanMerchantServiceTypes = masterDataService
				.selectAllMerchantProfileServiceType();

			if (entryBeanServiceTypes != null) {
			    for (EntryBean<String, String> entry : entryBeanServiceTypes) {
				serviceTypeMap.put(entry.getKey(), entry.getValue());
			    }
			}
			if (entryBeanStatus != null) {
			    for (EntryBean<String, String> entry : entryBeanStatus) {
				statusMap.put(entry.getKey(), entry.getValue());
			    }
			}
			if (entryBeanMerchantServiceTypes != null) {
			    for (EntryBean<String, String> entry : entryBeanMerchantServiceTypes) {
				merchantServiceTypeMap.put(entry.getKey(), entry.getValue());
			    }
			}

			List<ServiceProfileCSVTemplate> content = new ArrayList<ServiceProfileCSVTemplate>();
			List<ServiceProfile> serviceProfiles = page.getContent();
			if (serviceProfiles != null && !serviceProfiles.isEmpty()) {

			    DateFormat monthYearFormat = new SimpleDateFormat(StringUtils.PATTERN_MONTH_YEAR_PERSISTENCE);
			    DateFormat dateFormat = new SimpleDateFormat(StringUtils.PATTERN_DATE_PERSISTENCE);
			    DateFormat dateTimeFormat = new SimpleDateFormat(StringUtils.PATTERN_DATETIME_PERSISTENCE);
			    DateFormat monthYearFormatUI = new SimpleDateFormat(StringUtils.PATTERN_MONTH_YEAR_UI);
			    DateFormat dateFormatUI = new SimpleDateFormat(StringUtils.PATTERN_DATE_UI);
			    DateFormat dateTimeFormatUI = new SimpleDateFormat(StringUtils.PATTERN_DATETIME_UI);

			    for (ServiceProfile serviceProfile : serviceProfiles) {

				ServiceProfileCSVTemplate serviceProfileCSVTemplate = new ServiceProfileCSVTemplate();

				serviceProfileCSVTemplate.setMerchantId(serviceProfile.getMerchantId());
				MerchantProfile merchantProfile = serviceProfile.getMerchantProfile();
				if (merchantProfile != null) {
				    serviceProfileCSVTemplate.setMerchantName(merchantProfile.getMerchantNameEn());
				    serviceProfileCSVTemplate.setCompanyName(merchantProfile.getCompanyNameEn());
				    String merchantServiceTypeText = merchantServiceTypeMap.get(merchantProfile.getMerchantServiceType());
				    if (merchantServiceTypeText == null) {
					merchantServiceTypeText = merchantProfile.getMerchantServiceType();
				    }
				    serviceProfileCSVTemplate.setMerchantServiceType(merchantServiceTypeText);
				    serviceProfileCSVTemplate.setMerchantUrl(merchantProfile.getUrl());
				}

				serviceProfileCSVTemplate.setServiceId(serviceProfile.getServiceId());
				serviceProfileCSVTemplate.setContactPerson(serviceProfile.getContact1Name());
				serviceProfileCSVTemplate.setHost(serviceProfile.getHost());
				String serviceTypeText = serviceTypeMap.get(serviceProfile.getServiceType());
				if (serviceTypeText == null) {
				    serviceTypeText = serviceProfile.getServiceType();
				}
				serviceProfileCSVTemplate.setServiceType(serviceTypeText);
				serviceProfileCSVTemplate.setMdr(serviceProfile.getMdr());
				serviceProfileCSVTemplate.setServiceFee(serviceProfile.getServiceFee());
				if (serviceProfile.getBankGuaranteeExpireDate() != null) {
				    try {
					Date date = monthYearFormat.parse(serviceProfile.getBankGuaranteeExpireDate());
					String strUI = monthYearFormatUI.format(date);
					serviceProfileCSVTemplate.setBankGuaranteeExpireDate(strUI);
				    } catch (ParseException e) {
				    }
				}
				if (serviceProfile.getLaunchedDate() != null) {
				    try {
					Date date = dateFormat.parse(serviceProfile.getLaunchedDate());
					String strUI = dateFormatUI.format(date);
					serviceProfileCSVTemplate.setLaunchedDate(strUI);
				    } catch (ParseException e) {
				    }
				}
				String statusText = statusMap.get(serviceProfile.getServiceStatus());
				if (statusText == null) {
				    statusText = serviceProfile.getServiceStatus();
				}
				serviceProfileCSVTemplate.setStatus(statusText);

				if (serviceProfile.getCreateDate() != null) {
				    try {
					Date date = dateTimeFormat.parse(serviceProfile.getCreateDate());
					String strUI = dateTimeFormatUI.format(date);
					serviceProfileCSVTemplate.setCreateDate(strUI);
				    } catch (ParseException e) {
				    }
				}
				if (serviceProfile.getLastUpdateDate() != null) {
				    try {
					Date date = dateTimeFormat.parse(serviceProfile.getLastUpdateDate());
					String strUI = dateTimeFormatUI.format(date);
					serviceProfileCSVTemplate.setLastUpdateDate(strUI);
				    } catch (ParseException e) {
				    }
				}

				content.add(serviceProfileCSVTemplate);
			    }
			}

			if (!content.isEmpty()) {
			    String path = propertyService
				    .getProperty("com.fw.service.serviceprofile.ServiceProfileService.template.csv.path");
			    String encode = propertyService.getProperty("com.fw.service.serviceprofile.ServiceProfileService.encode.csv");
			    VelocityContext context = new VelocityContext();
			    String templatePath = this.getClass().getResource(path).getFile();
			    VelocityUtil vutil = new VelocityUtil(templatePath);

			    context.put(ServiceProfileCSVTemplate.TEMPLATE_ATTRIBUTE_SERVICE_PROFILE_LIST, content);

			    String text = vutil.getReportAsString(context);
			    if (text != null) {
				result = text.getBytes(encode);
			    }
			}
		    }
		}
	    }
	} catch (Exception e) {
	    log.error(e.getMessage(), e);
	}
	return result;
    }

    @Override
    public ServiceProfileBean getServiceProfileByServiceId(String serviceId) {
	ServiceProfileBean serviceProfileBean = null;
	try {
	    List<ServiceProfile> serviceProfiles = serviceProfilePersistenceService.selectByServiceIdAndStatus(serviceId, null);
	    if (serviceProfiles != null && !serviceProfiles.isEmpty()) {
		ServiceProfile serviceProfile = serviceProfiles.get(0);
		if (serviceProfile != null) {
		    serviceProfileBean = new ServiceProfileBean();
		    BeanUtils.copyProperties(serviceProfile, serviceProfileBean);
		    serviceProfileBean.setId(serviceProfile.getId());
		}
	    }
	} catch (Exception e) {
	    log.error(e, e);
	}
	return serviceProfileBean;
    }

}
